package utils

import (
	"fmt"
	"net/http"
	"runtime"
)

// ErrorCode 错误代码常量
const (
	// 成功代码
	CodeSuccess = 1000

	// 客户端错误 (1001-1999)
	CodeBadRequest     = 1001
	CodeUnauthorized   = 1002
	CodeForbidden      = 1003
	CodeNotFound       = 1004
	CodeValidationFail = 1005
	CodeDuplicateData  = 1006

	// 服务器错误 (2001-2999)
	CodeInternalError = 2001
	CodeDatabaseError = 2002
	CodeRedisError    = 2003
	CodeFileError     = 2004
	CodeNetworkError  = 2005

	// 业务逻辑错误 (3001-3999)
	CodeLoginFailed      = 3001
	CodePasswordWrong    = 3002
	CodeUserNotFound     = 3003
	CodePermissionDenied = 3004
	CodeDataNotFound     = 3005
)

// AppError 应用错误结构
type AppError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Detail  string `json:"detail,omitempty"`
	File    string `json:"file,omitempty"`
	Line    int    `json:"line,omitempty"`
}

// Error 实现error接口
func (e *AppError) Error() string {
	return fmt.Sprintf("[%d] %s: %s", e.Code, e.Message, e.Detail)
}

// NewError 创建新的应用错误
func NewError(code int, message string, detail ...string) *AppError {
	err := &AppError{
		Code:    code,
		Message: message,
	}

	if len(detail) > 0 {
		err.Detail = detail[0]
	}

	// 获取调用位置信息
	if _, file, line, ok := runtime.Caller(1); ok {
		err.File = file
		err.Line = line
	}

	return err
}

// 预定义常用错误
var (
	ErrBadRequest     = NewError(CodeBadRequest, "请求参数错误")
	ErrUnauthorized   = NewError(CodeUnauthorized, "未授权访问")
	ErrForbidden      = NewError(CodeForbidden, "访问被禁止")
	ErrNotFound       = NewError(CodeNotFound, "资源未找到")
	ErrValidationFail = NewError(CodeValidationFail, "数据验证失败")
	ErrDuplicateData  = NewError(CodeDuplicateData, "数据重复")

	ErrInternalError = NewError(CodeInternalError, "内部服务器错误")
	ErrDatabaseError = NewError(CodeDatabaseError, "数据库操作错误")
	ErrRedisError    = NewError(CodeRedisError, "Redis操作错误")
	ErrFileError     = NewError(CodeFileError, "文件操作错误")
	ErrNetworkError  = NewError(CodeNetworkError, "网络请求错误")

	ErrLoginFailed      = NewError(CodeLoginFailed, "登录失败")
	ErrPasswordWrong    = NewError(CodePasswordWrong, "密码错误")
	ErrUserNotFound     = NewError(CodeUserNotFound, "用户不存在")
	ErrPermissionDenied = NewError(CodePermissionDenied, "权限不足")
	ErrDataNotFound     = NewError(CodeDataNotFound, "数据不存在")
)

// ResponseData 统一响应结构
type ResponseData struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
	Error   *AppError   `json:"error,omitempty"`
}

// Success 成功响应
func Success(message string, data interface{}) *ResponseData {
	return &ResponseData{
		Code:    CodeSuccess,
		Message: message,
		Data:    data,
	}
}

// SuccessWithData 带数据的成功响应
func SuccessWithData(data interface{}) *ResponseData {
	return &ResponseData{
		Code:    CodeSuccess,
		Message: "操作成功",
		Data:    data,
	}
}

// ErrorResponse 错误响应
func ErrorResponse(err *AppError) *ResponseData {
	return &ResponseData{
		Code:    err.Code,
		Message: err.Message,
		Error:   err,
	}
}

// ErrorResponseWithMessage 带自定义消息的错误响应
func ErrorResponseWithMessage(err *AppError, message string) *ResponseData {
	return &ResponseData{
		Code:    err.Code,
		Message: message,
		Error:   err,
	}
}

// GetHTTPStatusCode 根据错误代码获取HTTP状态码
func GetHTTPStatusCode(code int) int {
	switch {
	case code == CodeSuccess:
		return http.StatusOK
	case code >= 1001 && code <= 1999:
		switch code {
		case CodeUnauthorized:
			return http.StatusUnauthorized
		case CodeForbidden:
			return http.StatusForbidden
		case CodeNotFound:
			return http.StatusNotFound
		default:
			return http.StatusBadRequest
		}
	case code >= 2001 && code <= 2999:
		return http.StatusInternalServerError
	case code >= 3001 && code <= 3999:
		return http.StatusBadRequest
	default:
		return http.StatusInternalServerError
	}
}

// WrapDatabaseError 包装数据库错误
func WrapDatabaseError(err error, detail string) *AppError {
	if err == nil {
		return nil
	}
	return NewError(CodeDatabaseError, "数据库操作失败", fmt.Sprintf("%s: %v", detail, err))
}

// WrapRedisError 包装Redis错误
func WrapRedisError(err error, detail string) *AppError {
	if err == nil {
		return nil
	}
	return NewError(CodeRedisError, "缓存操作失败", fmt.Sprintf("%s: %v", detail, err))
}

// WrapValidationError 包装验证错误
func WrapValidationError(field, message string) *AppError {
	return NewError(CodeValidationFail, "数据验证失败", fmt.Sprintf("%s: %s", field, message))
}
